10.5 性能

反射在带来“方便”的同时,也造成了很大的困扰。很多人对反射避之不及,因为它会造成很大的性能损失。但损失到底有多大?我们简单测试一下。

先看看直接赋值和反射赋值的性能差异。

type Data struct{ X int }

var d=new(Data)

func set(x int) { d.X=x }

func rset(x int) { v:=reflect.ValueOf(d).Elem() f:=v.FieldByName(“X”) f.Set(reflect.ValueOf(x)) }

func BenchmarkSet(b*testing.B) { for i:=0;i<b.N;i++ { set(100) } }

func BenchmarkRset(b*testing.B) { for i:=0;i<b.N;i++ { rset(100) } }

输出:

$go test-run None-bench. -benchmem

BenchmarkSet-4 2000000000 0.52 ns/op 0 B/op 0 allocs/op BenchmarkRset-4 10000000 154 ns/op 16 B/op 2 allocs/op

这差距有些吓人。改进一下,将反射数据“缓存”起来。

var v=reflect.ValueOf(d).Elem() var f=v.FieldByName(“X”)

func rset(x int) { f.Set(reflect.ValueOf(x)) }

输出:

$go test-run None-bench. -benchmem

BenchmarkSet-4 2000000000 0.54 ns/op 0 B/op 0 allocs/op BenchmarkRset-4 20000000 55.1 ns/op 8 B/op 1 allocs/op

改进后性能有所提升,但差距还是非常大。接下来,试试方法直接调用,和反射调用对比一下性能。

type Data struct{ X int }

func(x*Data)Inc() { x.X++ }

var d=new(Data) var v=reflect.ValueOf(d) var m=v.MethodByName(“Inc”)

func call() { d.Inc() }

func rcall() { m.Call(nil) }

输出:

$go test-run None-bench. -benchmem

BenchmarkCall-4 1000000000 2.23 ns/op 0 B/op 0 allocs/op BenchmarkRcall-4 10000000 167 ns/op 0 B/op 0 allocs/op

如对性能要求较高,那么须谨慎使用反射。